#include "libfactory.h"
#include "../build/AWSMReporter/soapH.h"
#include "../build/AWSMReporter/AWSMReporter.nsmap"

char * serviceName = "AWSMReporter";
char * uuid = "f9f2c29b-763d-44da-a09c-8837a4ae8ad4";

char * subject = "Incident on Route 66";
char * report = "On route 66...";
char * reporter = "schmidt";
char * dateTime;

char * get_service(struct soap *soap, char * wsdlAddress) {
	// return physical address of a service wsdl
	xmlDoc *doc = NULL;
	xmlNode *root = NULL;
	xmlNode *service = NULL;

	char * service_file;
	config_get_string(&service_file, "SERVICES_FILE");

	doc = xmlReadFile(service_file, NULL, XML_PARSE_NOWARNING);

	if (!doc) {
		fprintf(stderr, "AWSMReporter.c: deployment file %s doesn't exist",
				service_file);
		return NULL;
	}

	root = xmlDocGetRootElement(doc);
	service = root ->children;

	while (service) {
		if (strstr(xmlGetProp(service, "addressWsdl"), wsdlAddress)) {
			return xmlGetProp(service, "path");
		}
		service = service->next;
	}

	xmlFreeDoc(doc);

	return NULL;

}

int http_get(struct soap *soap) {
	// implements HTTP GET method
	char *s = strchr(soap->path, '?');
	if (!s || strcmp(s, "?wsdl"))
		return SOAP_GET_METHOD;
	FILE * f = fopen(get_service(soap, soap->path), "rb");
	if (!f)
		return 404;
	soap->http_content = "text/xml";
	soap_response(soap, SOAP_FILE);
	for (;;) {
		int r = fread(soap->tmpbuf, 1, sizeof(soap->tmpbuf), f);
		if (!r)
			break;
		if (soap_send_raw(soap, soap->tmpbuf, r))
			break;
	}
	fclose(f);
	soap_end_send(soap);
	return SOAP_OK;
}

void *process_request(void *soap) {
	pthread_detach(pthread_self());
	soap_serve((struct soap*) soap);
	soap_destroy((struct soap*) soap);
	// dealloc C++ data
	soap_end((struct soap*) soap);
	// dealloc data and clean up
	soap_done((struct soap*) soap);
	// detach soap struct
	free(soap);
	return NULL;
}

int main(int argc, char **argv) {

	struct soap soap;
	soap_init(&soap);
	soap.fget = http_get;

	soap.send_timeout = 5;
	soap.recv_timeout = 5;
	soap.accept_timeout = 30;
	// server stops after 1 hour of inactivity
	soap.max_keep_alive = 100;
	// max keep-alive sequence

	void *process_request(void*);
	struct soap *tsoap;
	pthread_t tid;
	SOAP_SOCKET m, s;

	m = soap_bind(&soap, NULL, 8084, 100);

	if (!soap_valid_socket(m)) {
		fprintf(stderr,
				"AWSMReporter.c: %s failed to start, port %d is busy\n",
				serviceName, 8084);
		exit(1);
	}

	get_time_string(&dateTime);

	//service_set_uuid(&uuid);

	fprintf(stderr, "AWSMReporter.c: %s started with id %s\n", serviceName,
			uuid);
	char * awsm_home;
	config_get_string(&awsm_home, "AWSM_HOME");
	service_deploy(serviceName, "http://localhost:8084/AWSMReporter?wsdl",
			strcat(awsm_home, "/build/AWSMReporter/AWSMReporter.wsdl"), uuid);

	struct timeval t_start, t_finish, t_elapsed, t_total_start, t_total_finish,
			t_total_elapsed;
	gettimeofday(&t_total_start, NULL);

	gettimeofday(&t_start, NULL);

	char * states = malloc(1024);
	sprintf(states, "<states>"
		"<state type='string' name='subject' length='%d'>%s</state>"
		"<state type='string' name='report' length='%d'>%s</state>"
		"<state type='string' name='reporter' length='%d'>%s</state>"
		"<state type='string' name='dateTime' length='%d'>%s</state>"
		"</states>", strlen(subject), subject, strlen(report), report, strlen(
			reporter), reporter, strlen(dateTime), dateTime);

	set_states(uuid, states);

	gettimeofday(&t_finish, NULL);
	timeval_subtract(&t_elapsed, &t_finish, &t_start);
	fprintf(stderr, "AWSMReporter.c: setStates used %.f ms\n", t_elapsed.tv_sec
			* 1000 + t_elapsed.tv_usec / 1.e3);

	gettimeofday(&t_start, NULL);

	char * target = malloc(256);
	if (argv[1]) {
		sprintf(target, "<interface value='%s' />", argv[1]);
	} else {
		strcpy(target, "<interface value='test.demo.services.AWSMReviewer'/>");
	}
	factory_adapt(serviceName, uuid, target);

	gettimeofday(&t_finish, NULL);
	timeval_subtract(&t_elapsed, &t_finish, &t_start);
	fprintf(stderr, "AWSMReporter.c: adaption used %.f ms\n", t_elapsed.tv_sec
			* 1000 + t_elapsed.tv_usec / 1.e3);

	gettimeofday(&t_total_finish, NULL);
	timeval_subtract(&t_total_elapsed, &t_total_finish, &t_total_start);
	fprintf(stderr, "AWSMReporter.c: entire migration used %.f ms\n",
			t_total_elapsed.tv_sec * 1000 + t_total_elapsed.tv_usec / 1.e3);

	for (;;) {
		s = soap_accept(&soap);
		if (!soap_valid_socket(s)) {
			if (soap.errnum) {
				soap_print_fault(&soap, stderr);
				exit(1);
			}
			fprintf(stderr, "AWSMReporter.c: server timed out\n");
			service_undeploy(serviceName, uuid);
			break;
		}
		fprintf(
				stderr,
				"[soap] AWSMReporter.c: request from IP %d.%d.%d.%d processed\n",
				(soap.ip >> 24) & 0xFF, (soap.ip >> 16) & 0xFF, (soap.ip >> 8)
						& 0xFF, soap.ip & 0xFF);
		tsoap = soap_copy(&soap);
		// make a safe copy
		if (!tsoap)
			break;
		pthread_create(&tid, NULL, (void*(*)(void*)) process_request,
				(void*) tsoap);
	}

	soap_done(&soap);
	// detach soap struct
	return 0;

}

int ns__getReport(struct soap *soap, void *_, char ** message) {
	*message = soap_malloc(soap, 1024);
	strcpy(*message, report);
	return SOAP_OK;
}

int ns__setReport(struct soap *soap, char *request, char ** message) {
	report = request;
	*message = soap_malloc(soap, 1024);
	sprintf(*message, "AWSMReporter.c: %s set", report);
	return SOAP_OK;
}

int ns__getSubject(struct soap *soap, void *_, char ** message) {
	*message = soap_malloc(soap, 1024);
	strcpy(*message, subject);
	return SOAP_OK;
}

int ns__setSubject(struct soap *soap, char *request, char ** message) {
	subject = request;
	*message = soap_malloc(soap, 1024);
	sprintf(*message, "AWSMReporter.c: %s set", subject);
	return SOAP_OK;
}

int ns__getDateTime(struct soap *soap, void *_, char ** message) {
	*message = soap_malloc(soap, 1024);
	strcpy(*message, dateTime);
	return SOAP_OK;
}

int ns__setDateTime(struct soap *soap, char *request, char ** message) {
	dateTime = request;
	*message = soap_malloc(soap, 1024);
	sprintf(*message, "AWSMReporter.c: %s set", dateTime);
	return SOAP_OK;
}

int ns__getReporter(struct soap *soap, void *_, char ** message) {
	*message = soap_malloc(soap, 1024);
	strcpy(*message, reporter);
	return SOAP_OK;
}

int ns__setReporter(struct soap *soap, char *request, char ** message) {
	reporter = request;
	*message = soap_malloc(soap, 1024);
	sprintf(*message, "AWSMReporter.c: %s set", reporter);
	return SOAP_OK;
}
